package com.openatc.agent.utils;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.openatc.comm.data.MessageData;
import com.openatc.core.common.IErrorEnumImplOuter;
import com.openatc.core.model.InnerError;
import com.openatc.core.model.RESTRet;
import com.openatc.core.util.RESTRetUtils;
import com.openatc.model.model.StatusPattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.logging.Logger;

import static com.openatc.core.common.IErrorEnumImplInner.E_104;
import static com.openatc.core.common.IErrorEnumImplInner.E_112;

/**
 * @author laoxia
 * @Date 2021/7/28 14:09
 * @Describetion
 */
@Component
public class RedisTemplateUtil {

    private String agenttype = "asc";
    private Gson gson = new Gson();
    private static Logger logger = Logger.getLogger(RedisTemplateUtil.class.toString());

    private String dataSource = "Cache";
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 向redis中添加一个集合
     *
     * @param key
     * @param set
     */
    public void addSet(String key, Set<String> set) {
        for (String value : set) {
            redisTemplate.opsForSet().add(key, value);
        }
    }

    /**
     * 删除redis中的一个集合元素
     *
     * @param key
     * @param set
     */
    public void removeSet(String key, Set<String> set) {
        for (String value : set) {
            if (redisTemplate.opsForSet().isMember(key, value)) {
                redisTemplate.opsForSet().remove(key, value);
            }
        }
    }

    /**
     * 获取key的所有值
     *
     * @param key
     * @return
     */
    public Set<String> getSet(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 获取匹配的key的列表
     *
     * @param pattern
     * @return
     */
    public Set<String> getKeys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    // 获取value
    public String getValue(String key){
        return redisTemplate.opsForValue().get(key);
    }

    // 获取value列表
    public List<String> getValues(Set<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }


    // 删除key
    public void delete(String key){
        redisTemplate.delete(key);
    }

    // 设置value
    public void setValue(String key, String value){
        redisTemplate.opsForValue().set(key, value);
    }

    // 发布消息
    public void publish(String channel, String message){
        redisTemplate.convertAndSend(channel, message);
    }
    /**
     * @Author: yangyi
     * @Date: 2022/1/5 9:42
     * @Description: get current pattern from redis
     */
    public StatusPattern getStatusPatternFromRedis (String agentId) {
        String key = agenttype + ":" + "status/pattern" + ":" + agentId;
        String value = redisTemplate.opsForValue().get(key);
        if(value == null)
            return null;
        MessageData messageData = gson.fromJson(value, MessageData.class);
        StatusPattern statusPattern = gson.fromJson(messageData.getData().getAsJsonObject(),StatusPattern.class);
        return statusPattern;
    }

    public JsonObject GetRedisInfo(String agent_lang_type){
        Properties info = redisTemplate.getRequiredConnectionFactory().getConnection().info("memory");
        Properties info2 = redisTemplate.getRequiredConnectionFactory().getConnection().info("clients");

        String str1 = null;
        String str2 = null;
        String str3 = null;
        String str4 = null;
        String str5 = null;
        String str6 = null;

        if(agent_lang_type.equals("cn")){
            str1 = "内存总量";
            str2 = "内存峰值";
            str3 = "进程占用内存";
            str4 = "系统总内存";
            str5 = "内存碎片率";
            str6 = "连接数";
        }
        else{
            str1 = "Used Memory";
            str2 = "Used Memory Peak";
            str3 = "Used Memory RSS";
            str4 = "Total System Memory";
            str5 = "Mem Fragmentation Ratio";
            str6 = "Connected Clients";
        }

        JsonObject jo = new JsonObject();
        jo.addProperty(str1, info.getProperty("used_memory_human"));
        jo.addProperty(str2, info.getProperty("used_memory_peak_human"));
        jo.addProperty(str3, info.getProperty("used_memory_rss_human"));
        jo.addProperty(str4, info.getProperty("total_system_memory_human"));
        jo.addProperty(str5, info.getProperty("mem_fragmentation_ratio"));
        jo.addProperty(str6, info2.getProperty("connected_clients"));

//        Properties info3 = redisTemplate.getRequiredConnectionFactory().getConnection().info("stats");

        return jo;
    }

    /**
     * 批量查询方案状态数据
     * @param agentidList
     * @return
     */
    public Map<String,MessageData> muliGetStatusPatternFromRedis(Set<String> agentidList) {
//        Set<String> keys = new HashSet<>();
//        for (String agentid : agentidList){
//            String key = agenttype + ":" + "status/pattern" + ":" + agentid;
//            keys.add(key);
//        }
        List<String> values = getValues(agentidList);
        Map<String,MessageData> map = new HashMap<>();
        for (String value : values){
            if (value != null){
                StatusPattern statusPattern = null;
                try{
                    MessageData messageData = gson.fromJson(value, MessageData.class);
                    map.put(messageData.getAgentid(),messageData);
//                    statusPattern = gson.fromJson(messageData.getData().getAsJsonObject(),StatusPattern.class);
                }
                catch (Exception e){
                    logger.warning("MessageData json error!" + e.getMessage());
                    continue;
                }
            }
        }
        return map;
    }


    /**
     * 批量保存数据至redis
     * @param dataList
     * @param expire
     */
    public void mulitSavaMessageData(List<MessageData> dataList, long expire) {
//        //使用pipeline方式
//        redisTemplate.executePipelined(new RedisCallback<List<Object>>() {
//            @Override
//            public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
//                for (MessageData msg : dataList) {
//                    String key = "response:" + msg.getInfotype() + ":" + msg.getAgentid();
//                    byte[] rawKey = redisTemplate.getKeySerializer().serialize(key);
//                    connection.setEx(rawKey, redisTemplate.getValueSerializer().serialize(msg));
//                }
//                return null;
//            }
//        });
        // todo 暂时采用此方法，后面替换为批量保存
        for (MessageData messageData : dataList) {
            String key = "response:" + messageData.getInfotype() + ":" + messageData.getAgentid();
            setValue(key,gson.toJson(messageData));
        }

    }

    /**
     * 获取缓存数据
     * @param requestData
     * @return
     */
    public RESTRet getCacheData(MessageData requestData) {
        String agentid = requestData.getAgentid();
        String value = getDateFromCache(agentid,requestData.getInfotype());
        if (value == null) {
            InnerError innerErrorObj = RESTRetUtils.innerErrorObj(agentid, E_112, null);
            return RESTRetUtils.errorDetialObj(IErrorEnumImplOuter.E_4001,innerErrorObj);
        }

        MessageData messageData;
        try {
            messageData = gson.fromJson(value,MessageData.class);
        } catch (JsonSyntaxException e) {
            logger.warning("Json Parse Exception: " + e.getMessage());
            InnerError innerErrorObj = RESTRetUtils.innerErrorObj(agentid, E_104, null);
            return RESTRetUtils.errorDetialObj(IErrorEnumImplOuter.E_4001,innerErrorObj);
        }
        messageData.setSource(dataSource);
        return RESTRetUtils.successObj(messageData);
    }

    private String getDateFromCache(String agentid, String infotype) {
        String key = "response:" + infotype + ":" + agentid;
        return this.getValue(key);
    }
}
